// import com.alibaba.druid.FastsqlException;
// import com.alibaba.druid.sql.ast.SQLExpr;
// import com.alibaba.druid.sql.ast.SQLName;
// import com.alibaba.druid.sql.ast.SQLObject;
// import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
// import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
// import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerObjectImpl;
// import com.alibaba.druid.sql.dialect.sqlserver.visitor.SQLServerASTVisitor;
// import com.alibaba.druid.util.FnvHash;

// import java.io.IOException;
// import java.util.Collections;
// import java.util.List;
#include "SQLServerObjectReferenceExpr.h"
#include "../../../../ast/SQLExpr.h"
#include "../../../../ast/SQLObject.h"
#include "../../../../ast/expr/SQLIdentifierExpr.h"
#include "../../../../ast/expr/SQLPropertyExpr.h"
#include "../../../../ast/statement/SQLColumnDefinition.h"
#include "../../visitor/SQLServerASTVisitor.h"
#include "../../../../../utils/FnvHash.h"
#include "../../../../../utils/instanceof.h"
#include "../../../../../Exception/FastsqlException.h"
#include "../../../../../Exception/IllegalArgumentException.h"

SQLServerObjectReferenceExpr::SQLServerObjectReferenceExpr()
{
}

SQLServerObjectReferenceExpr::SQLServerObjectReferenceExpr(SQLExpr_ptr owner)
{
  if (instanceof <SQLExpr, SQLIdentifierExpr>(owner))
  {
    this->database = (std::dynamic_pointer_cast<SQLIdentifierExpr>(owner))->getName();
  }
  else if (instanceof <SQLExpr, SQLPropertyExpr>(owner))
  {
    SQLPropertyExpr_ptr propExpr = std::dynamic_pointer_cast<SQLPropertyExpr>(owner);

    this->server = (std::dynamic_pointer_cast<SQLIdentifierExpr>(propExpr->getOwner()))->getName();
    this->database = propExpr->getName();
  }
  else
  {
    throw new IllegalArgumentException(owner->toString());
  }
}

string_ptr SQLServerObjectReferenceExpr::getSimpleName()
{
  if (schema != nullptr)
  {
    return schema;
  }

  if (database != nullptr)
  {
    return database;
  }
  return server;
}

// @Override
void SQLServerObjectReferenceExpr::accept0(SQLServerASTVisitor_ptr visitor)
{
  visitor->visit(SharedObject(SQLServerObjectReferenceExpr));
  visitor->endVisit(SharedObject(SQLServerObjectReferenceExpr));
}

void SQLServerObjectReferenceExpr::output(std::stringstream * buf)
{
  try
  {
    BOOL_ptr flag = BOOL::FALSE;
    if (server != nullptr)
    {
      (*buf)<<server->c_str();
      flag = BOOL::TRUE;
    }

    if (flag)
    {
      (*buf)<<".";
    }
    if (database != nullptr)
    {
      (*buf)<<database->c_str();
      flag = BOOL::TRUE;
    }

    if (flag)
    {
      (*buf)<<".";
    }

    if (schema != nullptr)
    {
      (*buf)<<schema->c_str();
      flag = BOOL::TRUE;
    }
  }
  catch (const std::exception &e)
  {
    std::string tmp = "output error";
    tmp += e.what();
    throw new FastsqlException(make_string_ptr(tmp));
  }
}

string_ptr SQLServerObjectReferenceExpr::getServer()
{
  return server;
}

void SQLServerObjectReferenceExpr::setServer(string_ptr server)
{
  this->server = server;
}

string_ptr SQLServerObjectReferenceExpr::getDatabase()
{
  return database;
}

void SQLServerObjectReferenceExpr::setDatabase(string_ptr database)
{
  this->database = database;
}

string_ptr SQLServerObjectReferenceExpr::getSchema()
{
  return schema;
}

void SQLServerObjectReferenceExpr::setSchema(string_ptr schema)
{
  this->schema = schema;
}

SQLObject_ptr SQLServerObjectReferenceExpr::clone()
{
  SQLObject_ptr clone_tmp = std::shared_ptr<SQLServerObjectReferenceExpr>(new SQLServerObjectReferenceExpr());
  std::shared_ptr<SQLServerObjectReferenceExpr> x = std::dynamic_pointer_cast<SQLServerObjectReferenceExpr>(clone_tmp);
  // SQLServerObjectReferenceExpr x = new SQLServerObjectReferenceExpr();

  x->server = server;
  x->database = database;
  x->schema = schema;

  x->schemaHashCode64 = schemaHashCode64;
  x->hashCode64_ = hashCode64_;

  return x;
}

long SQLServerObjectReferenceExpr::nameHashCode64()
{
  if (schemaHashCode64 == 0 && schema != nullptr)
  {
    schemaHashCode64 = FnvHash::hashCode64(schema);
  }
  return schemaHashCode64;
}

// @Override
long SQLServerObjectReferenceExpr::hashCode64()
{
  if (hashCode64_ == 0)
  {
    if (server == nullptr)
    {
      hashCode64_ = (new SQLPropertyExpr(
                         SQLPropertyExpr_ptr(new SQLPropertyExpr(server, database)),
                         schema))
                        ->hashCode64();
    }
    else
    {
      hashCode64_ = (new SQLPropertyExpr(database, schema))
                        ->hashCode64();
    }
  }
  return hashCode64_;
}

// @Override
SQLObject_ptr SQLServerObjectReferenceExpr::getResolvedColumn()
{
  return nullptr;
}

SQLObject_list_ptr SQLServerObjectReferenceExpr::getChildren()
{
  SQLObject_list_ptr tmp = std::make_shared<std::list<SQLObject_ptr>>();
  return tmp;
}
